home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 06 - 1990 / 06.03 Mar 90 / Debug CDEF Code / date_cdef.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-02-10  |  21.0 KB  |  663 lines  |  [TEXT/KAHL]

  1. /******** System includes ********/
  2. #include <Quickdraw.h>
  3. #include <ControlMgr.h>
  4. #include <MemoryMgr.h>
  5. #include <OSUtil.h>
  6. #include <FontMgr.h>
  7. #include <SetupA4.h>
  8. /**********************************/
  9.  
  10. /******** defines ********/
  11. #define NULL 0L
  12. #define CONTROL_WINDOW        ( (*my_control)->contrlOwner )
  13. #define CONTROL_VISIBLE        ( (*my_control)->contrlVis )
  14. #define CONTROL_HILITE        ( (*my_control)->contrlHilite )
  15. #define CONTROL_VALUE        ( (*my_control)->contrlValue )
  16. #define CONTROL_MIN            ( (*my_control)->contrlMin )
  17. #define CONTROL_MAX            ( (*my_control)->contrlMax )
  18. #define CONTROL_TITLE        ( (*my_control)->contrlTitle )
  19. #define CONTROL_RECT        (**(DATE_TIME_CONTROL_HDL)\
  20.                                 ((*my_control)->contrlData)).control_rect
  21. #define CONTROL_RECT_LEFT    (**(DATE_TIME_CONTROL_HDL)\
  22.                                 ((*my_control)->contrlData)).control_rect.left
  23. #define CONTROL_RECT_TOP    (**(DATE_TIME_CONTROL_HDL)\
  24.                                 ((*my_control)->contrlData)).control_rect.top
  25. #define CONTROL_RECT_RIGHT    (**(DATE_TIME_CONTROL_HDL)\
  26.                                 ((*my_control)->contrlData)).control_rect.right
  27. #define CONTROL_RECT_BOTTOM    (**(DATE_TIME_CONTROL_HDL)\
  28.                                 ((*my_control)->contrlData)).control_rect.bottom
  29. #define CONTROL_DATE_TIME    (**(DATE_TIME_CONTROL_HDL)\
  30.                                 ((*my_control)->contrlData)).date_time
  31. #define CONTROL_FONT_WIDTH    (**(DATE_TIME_CONTROL_HDL)\
  32.                                 ((*my_control)->contrlData)).font_width
  33. #define CONTROL_FONT_HEIGHT    (**(DATE_TIME_CONTROL_HDL)\
  34.                                 ((*my_control)->contrlData)).font_height
  35. #define CONTROL_ITEM_RECT    (**(DATE_TIME_CONTROL_HDL)\
  36.                                 ((*my_control)->contrlData)).item_rect
  37. #define CONTROL_ITEM_HILITE    (**(DATE_TIME_CONTROL_HDL)\
  38.                                 ((*my_control)->contrlData)).item_hilite
  39. #define CONTROL_ITEM_UPDATE    (**(DATE_TIME_CONTROL_HDL)\
  40.                                 ((*my_control)->contrlData)).item_update
  41. #define CONTROL_CHAR_POS    (**(DATE_TIME_CONTROL_HDL)\
  42.                                 ((*my_control)->contrlData)).char_point
  43. #define CONTROL_CHAR_ARY    (**(DATE_TIME_CONTROL_HDL)\
  44.                                 ((*my_control)->contrlData)).character
  45. #define CONTROL_HILITED        (**(DATE_TIME_CONTROL_HDL)\
  46.                                 ((*my_control)->contrlData)).item_hilited
  47. #define CONTROL_LST_HILITED    (**(DATE_TIME_CONTROL_HDL)\
  48.                                 ((*my_control)->contrlData)).last_hilite
  49. #define NEW_CLIP            (**(DATE_TIME_CONTROL_HDL)\
  50.                                 ((*my_control)->contrlData)).new_clip
  51. #define OLD_CLIP            (**(DATE_TIME_CONTROL_HDL)\
  52.                                 ((*my_control)->contrlData)).old_clip
  53. #define DE_BOUNCER            (**(DATE_TIME_CONTROL_HDL)\
  54.                                 ((*my_control)->contrlData)).de_bouncer
  55. #define NUM_DAYS            (**(DATE_TIME_CONTROL_HDL)\
  56.                                 ((*my_control)->contrlData)).num_days
  57. #define NEW_DATE_TIME        (**(DATE_TIME_CONTROL_HDL)\
  58.                                 ((*my_control)->contrlData)).new_date_time_rec
  59. #define MONTH_PART_CODE        1
  60. #define DAY_PART_CODE        2
  61. #define YEAR_PART_CODE        3
  62. #define HOUR_PART_CODE        4
  63. #define MINUTE_PART_CODE    5
  64. #define UP_ARROW            6
  65. #define DOWN_ARROW            7
  66. #define CHARACTER_OFFSET    0
  67. #define DATE_TIME_OFFSET    8
  68. #define TOP_DOWN_MARGIN        4
  69. #define NUM_CHARS            13        
  70. #define NUM_PARTS            8
  71. #define CONTROL_FONT        systemFont
  72. #define CONTROL_FONT_SIZE    0
  73. #define CONTROL_FONT_STYLE    0
  74. #define DELAY                7
  75. /**********************************/
  76.  
  77.  
  78. /******** Global variables ********/
  79. /* These guys must be put in a structure */
  80. typedef struct {
  81.     DateTimeRec date_time ;            /* current time as set by the control */
  82.     Rect item_rect[NUM_PARTS] ;        /* item rect array */
  83.     int font_width ;                /* font width */
  84.     int font_height ;                /* font height */
  85.     int item_hilite[NUM_PARTS] ;    /* item hilite array */
  86.     int item_update[NUM_PARTS] ;    /* item update array */
  87.     Point char_point[NUM_CHARS] ;    /* pen position array for each character */
  88.     int character[NUM_CHARS] ;        /* character array */
  89.     int item_hilited ;                /* current item hilited */
  90.     int last_hilite ;                /* last item hilited */
  91.     RgnHandle old_clip ;            /* scratch rgnhandle */
  92.     RgnHandle new_clip ;            /* scratch rgnhandle */
  93.     Rect control_rect ;                /* control rect */
  94.     int de_bouncer ;                /* up/down arrow click delay */
  95.     int num_days[12] ;                /* days in month array */
  96.     DateTimeRec new_date_time_rec ;    /* date time rect provide for application */
  97. } DATE_TIME_CONTROL, *DATE_TIME_CONTROL_PTR, **DATE_TIME_CONTROL_HDL ;
  98. /**********************************/
  99.  
  100. /******** Subroutine prototypes ********/
  101. pascal long main( int, ControlHandle, int, long ) ;
  102. void doDrawControl( long, ControlHandle ) ;
  103. long doTestControl( long, ControlHandle ) ;
  104. void doCalcCRgns( RgnHandle, ControlHandle ) ;
  105. void doInitControl( ControlHandle ) ;
  106. void doTrackControl( int, ControlHandle ) ;
  107. void Date2Chars( DateTimeRec *, int * ) ;
  108. /****************************************/
  109.  
  110. /******** Bitmap for arrows ***************/
  111. char bits[2*18] = {
  112. 0x3F, 0x80, 
  113. 0x40, 0x40, 
  114. 0x84, 0x20, 
  115. 0x8E, 0x20, 
  116. 0x9F, 0x20, 
  117. 0xBF, 0xA0, 
  118. 0x8E, 0x20, 
  119. 0x8E, 0x20, 
  120. 0x80, 0x20, 
  121. 0x80, 0x20, 
  122. 0x8E, 0x20, 
  123. 0x8E, 0x20, 
  124. 0xBF, 0xA0, 
  125. 0x9F, 0x20, 
  126. 0x8E, 0x20, 
  127. 0x84, 0x20, 
  128. 0x40, 0x40, 
  129. 0x3F, 0x80 } ;
  130. /****************************************/
  131.  
  132. /******** CDEF 2 call with proc id 16*2 32 ********/
  133. pascal long main( varCode, my_control, message, param )
  134. int varCode ;
  135. ControlHandle my_control ;
  136. int message ;
  137. long param ;
  138. {
  139.     GrafPtr old_port ;
  140.     PenState pen_state ;
  141.     int i ;
  142.     Point p ;
  143.     long result ;
  144.  
  145.     /* Set up a4 */
  146.     RememberA0( ) ;
  147.     SetUpA4( ) ;
  148.     
  149.     /* Initialize function result */
  150.     result = 0 ;
  151.     
  152.     /* Initial setup */
  153.     if( ( (**my_control).contrlData == NULL ) && ( message != initCntl ) ) {
  154.         return result ;
  155.     }else if( (**my_control).contrlData != NULL ) {
  156.         HLock( (**my_control).contrlData ) ;
  157.     }
  158.     HLock( my_control ) ;
  159.     
  160.     /* Save port information */
  161.     GetPort( &old_port ) ;
  162.     SetPort( CONTROL_WINDOW ) ;
  163.     GetPenState( &pen_state ) ;
  164.     PenNormal( ) ;
  165.     
  166.     /* Set the font */
  167.     TextFont( CONTROL_FONT ) ;
  168.     TextFace( CONTROL_FONT_STYLE ) ;
  169.     TextSize( CONTROL_FONT_SIZE ) ;
  170.     
  171.     /* Check for control being repositioned, or date being set manually by program */
  172.     if( message != initCntl ) {
  173.         /* If rects do not match */
  174.         if( ( (*my_control)->contrlRect.top != CONTROL_RECT_TOP ) || 
  175.               ( (*my_control)->contrlRect.left != CONTROL_RECT_LEFT ) ) {
  176.             /* Update item rects */
  177.             for( i = 0; i<NUM_PARTS;i++ ) {
  178.                 OffsetRect( &CONTROL_ITEM_RECT[i], 
  179.                             (*my_control)->contrlRect.left - CONTROL_RECT_LEFT,
  180.                             (*my_control)->contrlRect.top - CONTROL_RECT_TOP ) ;
  181.             }
  182.             /* Now update character rects */
  183.             p.h = (*my_control)->contrlRect.left - CONTROL_RECT_LEFT ;
  184.             p.v = (*my_control)->contrlRect.top - CONTROL_RECT_TOP ;
  185.             for( i = 0; i<NUM_CHARS;i++ ) {
  186.                 AddPt( p, &CONTROL_CHAR_POS[i] ) ;
  187.             }
  188.             OffsetRect( &CONTROL_RECT, 
  189.                             (*my_control)->contrlRect.left - CONTROL_RECT_LEFT,
  190.                             (*my_control)->contrlRect.top - CONTROL_RECT_TOP ) ;
  191.         }
  192.         /* Now check to see if time has changed */
  193.         if( ( NEW_DATE_TIME.year != CONTROL_DATE_TIME.year ) ||
  194.             ( NEW_DATE_TIME.month != CONTROL_DATE_TIME.month ) ||
  195.             ( NEW_DATE_TIME.day != CONTROL_DATE_TIME.day ) ||
  196.             ( NEW_DATE_TIME.hour != CONTROL_DATE_TIME.hour ) ||
  197.             ( NEW_DATE_TIME.minute != CONTROL_DATE_TIME.minute ) ) {
  198.             CONTROL_DATE_TIME = NEW_DATE_TIME ;
  199.             Date2Chars( &CONTROL_DATE_TIME, CONTROL_CHAR_ARY ) ;
  200.             doDrawControl( 0, my_control ) ;
  201.         }
  202.     }
  203.  
  204.     /* Now handle control messages */
  205.     switch( message ) {
  206.     case initCntl:                        /* Initialize control */
  207.         doInitControl( my_control ) ;
  208.         break ;
  209.     case drawCntl:                        /* draw the control */
  210.         if( CONTROL_VISIBLE ) {
  211.             doDrawControl( param, my_control) ;
  212.         }
  213.         break ;
  214.     case testCntl:                        /* test where mouse button was pressed */
  215.         result = doTestControl( param, my_control ) ;
  216.         break ;
  217.     case calcCRgns:                        /* calculate controls region */
  218.         param = param & 0x00FFFFFF ;    /* Mask out hi byte */
  219.         doCalcCRgns( (RgnHandle)param, my_control ) ;
  220.         break ;
  221.     case autoTrack:                        /* track mouse hits */
  222.         doTrackControl( param, my_control ) ;
  223.         break ;
  224.     case dispCntl:                        /* dispose data storage for control */
  225.         DisposeRgn( OLD_CLIP ) ;
  226.         DisposeRgn( NEW_CLIP ) ;
  227.         DisposHandle( (**my_control).contrlData ) ;
  228.         break ;
  229.     case posCntl:                        /* Handled by default */
  230.     case dragCntl:
  231.         break ;
  232.     }
  233.     
  234.     /* Restore grafport */
  235.     SetPenState( &pen_state ) ;
  236.     SetPort( old_port ) ;
  237.     
  238.     /* Unlock handle to data to minimize heap fragmentation */
  239.     if( (**my_control).contrlData != NULL ) {
  240.         HUnlock( (**my_control).contrlData ) ;
  241.     }
  242.     
  243.     /* Restore a4 */
  244.     RestoreA4( ) ;
  245.     
  246.     return result ;
  247. }
  248. void doInitControl( my_control )
  249. ControlHandle my_control ;
  250. {
  251.     FontInfo font_info ;
  252.     Rect box ;
  253.     int i ;
  254.     char **hdl ;
  255.     
  256.     /* Allocate and lock data storage */
  257.     (**my_control).contrlData = NewHandle( sizeof( DATE_TIME_CONTROL ) ) ;
  258.     if( (**my_control).contrlData == NULL ) {
  259.         return ;
  260.     }
  261.     HLock( (**my_control).contrlData ) ;
  262.     
  263.     /* Set up controls rect and init data area */
  264.     SetRect( &CONTROL_RECT, 0, 0, 140, 24 ) ;
  265.     OffsetRect( &CONTROL_RECT, (*my_control)->contrlRect.left, 
  266.                 (*my_control)->contrlRect.top ) ;
  267.     (*my_control)->contrlAction = (ProcPtr)-1 ;
  268.     OLD_CLIP = NewRgn( ) ;
  269.     NEW_CLIP = NewRgn( ) ;
  270.     
  271.     /* Initialize time structure */
  272.     GetTime( &CONTROL_DATE_TIME ) ;
  273.     Date2Chars( &CONTROL_DATE_TIME, CONTROL_CHAR_ARY ) ;
  274.     NEW_DATE_TIME = CONTROL_DATE_TIME ;
  275.     
  276.     /* Now init character rects */
  277.     /* Get the font information */
  278.     GetFontInfo( &font_info ) ;
  279.     
  280.     /* Get height and width */
  281.     CONTROL_FONT_WIDTH = font_info.widMax - 6 ;
  282.     CONTROL_FONT_HEIGHT = font_info.ascent ;
  283.     
  284.     /* Calculate item rects now */
  285.     box = CONTROL_RECT ;
  286.     box.top = box.top + TOP_DOWN_MARGIN ;
  287.     box.bottom = box.top + CONTROL_FONT_HEIGHT ;
  288.     box.left = CONTROL_RECT_LEFT + DATE_TIME_OFFSET ;
  289.     box.right = box.left + 2*CONTROL_FONT_WIDTH + CHARACTER_OFFSET ;
  290.     /* Init char points */
  291.     for( i=0;i<NUM_CHARS;i++){
  292.         CONTROL_CHAR_POS[i].v = box.bottom ;
  293.     }
  294.     box.bottom += 2 ;
  295.     
  296.     i = 0 ;
  297.     /* Calculate total rect */
  298.     CONTROL_ITEM_RECT[0] = CONTROL_RECT ;
  299.     
  300.     /* Calculate month rect and character points */
  301.     CONTROL_ITEM_RECT[MONTH_PART_CODE] = box ;
  302.     CONTROL_CHAR_POS[i++].h = box.left ;
  303.     CONTROL_CHAR_POS[i++].h = box.left + CHARACTER_OFFSET + CONTROL_FONT_WIDTH ;
  304.     
  305.     /* Now calc position for first slash */
  306.     CONTROL_CHAR_POS[i++].h = box.right + CHARACTER_OFFSET ;
  307.     
  308.     /* Calculate day rect and character points */
  309.     OffsetRect( &box, ( CONTROL_FONT_WIDTH + 2*CHARACTER_OFFSET + 
  310.                 ( box.right - box.left ) ),0 ) ;
  311.     CONTROL_ITEM_RECT[DAY_PART_CODE] = box ;
  312.     CONTROL_CHAR_POS[i++].h = box.left ;
  313.     CONTROL_CHAR_POS[i++].h = box.left + CHARACTER_OFFSET + CONTROL_FONT_WIDTH ;
  314.     
  315.     /* Now calc position for second slash */
  316.     CONTROL_CHAR_POS[i++].h = box.right + CHARACTER_OFFSET ;
  317.     
  318.     /* Calculate year rect and character points */
  319.     OffsetRect( &box, ( CONTROL_FONT_WIDTH + 2*CHARACTER_OFFSET + 
  320.                 ( box.right - box.left ) ),0 ) ;
  321.     CONTROL_ITEM_RECT[YEAR_PART_CODE] = box ;
  322.     CONTROL_CHAR_POS[i++].h = box.left ;
  323.     CONTROL_CHAR_POS[i++].h = box.left + CHARACTER_OFFSET + CONTROL_FONT_WIDTH ;
  324.  
  325.     /* Calculate hour rect and character points */
  326.     OffsetRect( &box, ( DATE_TIME_OFFSET + ( box.right - box.left ) ),0 ) ;
  327.     CONTROL_ITEM_RECT[HOUR_PART_CODE] = box ;
  328.     CONTROL_CHAR_POS[i++].h = box.left ;
  329.     CONTROL_CHAR_POS[i++].h = box.left + CHARACTER_OFFSET + CONTROL_FONT_WIDTH ;
  330.  
  331.     /* Now calc position for colon */
  332.     CONTROL_CHAR_POS[i++].h = box.right + CHARACTER_OFFSET ;
  333.  
  334.     /* Calculate minute rect and character points */
  335.     OffsetRect( &box, ( CONTROL_FONT_WIDTH - 4 + 2*CHARACTER_OFFSET + 
  336.                 ( box.right - box.left ) ),0 ) ;
  337.     CONTROL_ITEM_RECT[MINUTE_PART_CODE] = box ;
  338.     CONTROL_CHAR_POS[i++].h = box.left ;
  339.     CONTROL_CHAR_POS[i++].h = box.left + CHARACTER_OFFSET + CONTROL_FONT_WIDTH ;
  340.  
  341.     /* Calculate up and down buttons rects */
  342.     OffsetRect( &box, ( DATE_TIME_OFFSET + ( box.right - box.left ) ),0 ) ;
  343.     box.top -= 2 ;
  344.     box.right = box.left + 11 ;
  345.     box.bottom = box.top + 9 ;
  346.     CONTROL_ITEM_RECT[UP_ARROW] = box ;
  347.     OffsetRect( &box, 0, 9 ) ;
  348.     CONTROL_ITEM_RECT[DOWN_ARROW] = box ;
  349.  
  350.     /* Zero all the update and hilite arrays out */
  351.     for( i=0;i<NUM_PARTS;i++) {
  352.         CONTROL_ITEM_UPDATE[i] = TRUE ;
  353.         CONTROL_ITEM_HILITE[i] = FALSE ;
  354.     }
  355.     
  356.     /* Init control hilites */
  357.     CONTROL_HILITED = 0 ;
  358.     CONTROL_LST_HILITED = 0 ;
  359.     
  360.     /* This is the number of times autoTrack must be called before updating date */
  361.     DE_BOUNCER = DELAY ;
  362.  
  363.     /* Number of days in the month */
  364.     NUM_DAYS[0] = 31 ;
  365.     NUM_DAYS[1] = 28 ;
  366.     NUM_DAYS[2] = 31 ;
  367.     NUM_DAYS[3] = 30 ;
  368.     NUM_DAYS[4] = 31 ;
  369.     NUM_DAYS[5] = 30 ;
  370.     NUM_DAYS[6] = 31 ;
  371.     NUM_DAYS[7] = 31 ;
  372.     NUM_DAYS[8] = 30 ;
  373.     NUM_DAYS[9] = 31 ;
  374.     NUM_DAYS[10] = 30 ;
  375.     NUM_DAYS[11] = 31 ;
  376.     
  377.     /* Handle leap years */
  378.     /* Note: year MOD 4 handles the leap year every 4 years but this does not take into
  379.        account the fact that every 4 centuries the leap year is skipped.  This will
  380.        happen again in the year 2000, which by our algorithm is a leap year, but in
  381.        acuality is not.  If this code is still in use till the year 2000 I will gladly
  382.        update it. */
  383.     if( ( CONTROL_DATE_TIME.year % 4 ) == 0 ) {
  384.         NUM_DAYS[1] = 29 ;
  385.     }else{
  386.         NUM_DAYS[1] = 28 ;
  387.     }
  388.  
  389.     return ;
  390. }
  391. void doDrawControl( parameter, my_control )
  392. long parameter ;
  393. ControlHandle my_control ;
  394. {
  395.     BitMap arrows ;
  396.     Rect box ;
  397.     Rect box2 ;
  398.     int i ;
  399.  
  400.     /* Save old clip region */
  401.     if( OLD_CLIP != NULL && NEW_CLIP != NULL ) {
  402.         GetClip( OLD_CLIP ) ;
  403.         RectRgn( NEW_CLIP, &CONTROL_RECT ) ;
  404.         SectRgn( OLD_CLIP, NEW_CLIP, NEW_CLIP ) ;
  405.         SetClip( NEW_CLIP ) ;
  406.  
  407.         /* Set update and hilite array */
  408.         if( parameter >= 0 && parameter < NUM_PARTS ) { 
  409.             CONTROL_ITEM_UPDATE[parameter] = TRUE ;
  410.         }
  411.         if( CONTROL_HILITE > 0 && CONTROL_HILITE < UP_ARROW ) { 
  412.             CONTROL_ITEM_HILITE[CONTROL_HILITE] = TRUE ;
  413.             CONTROL_HILITED = CONTROL_HILITE ;
  414.             CONTROL_LST_HILITED = CONTROL_HILITED ;
  415.             CONTROL_ITEM_UPDATE[UP_ARROW] = TRUE ;
  416.         }else if( CONTROL_HILITE == 0 ) {
  417.             CONTROL_HILITED = 0 ;
  418.             CONTROL_ITEM_UPDATE[UP_ARROW] = TRUE ;
  419.         }else if( CONTROL_HILITE == UP_ARROW || CONTROL_HILITE == DOWN_ARROW ) {
  420.             CONTROL_HILITED = CONTROL_LST_HILITED ;
  421.             CONTROL_ITEM_HILITE[CONTROL_LST_HILITED] = TRUE ;
  422.             CONTROL_ITEM_UPDATE[CONTROL_LST_HILITED] = TRUE ;
  423.             CONTROL_ITEM_UPDATE[UP_ARROW] = TRUE ;
  424.         }
  425.         for( i=0;i<NUM_PARTS;i++ ) {
  426.             if( parameter == 0 ) CONTROL_ITEM_UPDATE[i] = TRUE ;
  427.             if( parameter == i ) CONTROL_ITEM_UPDATE[i] = TRUE ;
  428.             if( ( CONTROL_ITEM_HILITE[i] ) && ( i != CONTROL_HILITED )  && 
  429.                 ( CONTROL_HILITED < UP_ARROW ) ) {
  430.                 CONTROL_ITEM_HILITE[i] = FALSE ;
  431.                 CONTROL_ITEM_UPDATE[i] = TRUE ;
  432.             }
  433.         }
  434.  
  435.         /* Now do drawing */
  436.         for( i=0;i<NUM_PARTS;i++ ) {
  437.             if( CONTROL_ITEM_UPDATE[i] ) {
  438.                 CONTROL_ITEM_UPDATE[i] = FALSE ;        
  439.                 switch( i ) {
  440.                 case 0:
  441.                     /* Frame the control */
  442.                     box = CONTROL_RECT ;
  443.                     if( parameter == 0 ) {
  444.                         EraseRect( &box ) ;
  445.                     }
  446.                     box.bottom -= 2 ;
  447.                     box.right -= 2 ;
  448.                     FrameRect( &box ) ;
  449.                     /* Now draw the shadow */
  450.                     MoveTo( box.left+1, box.bottom ) ;
  451.                     LineTo( box.right, box.bottom ) ;
  452.                     LineTo( box.right, box.top+1 ) ;
  453.                     /* Also draw the slashes and colon here */
  454.                     MoveTo( CONTROL_CHAR_POS[2].h, CONTROL_CHAR_POS[2].v ) ;
  455.                     DrawChar( CONTROL_CHAR_ARY[2] ) ;
  456.                     MoveTo( CONTROL_CHAR_POS[5].h, CONTROL_CHAR_POS[5].v ) ;
  457.                     DrawChar( CONTROL_CHAR_ARY[5] ) ;
  458.                     MoveTo( CONTROL_CHAR_POS[10].h, CONTROL_CHAR_POS[10].v ) ;
  459.                     DrawChar( CONTROL_CHAR_ARY[10] ) ;
  460.                     break ;
  461.                 case MONTH_PART_CODE:
  462.                     /* Draw month characters */
  463.                     EraseRect( &CONTROL_ITEM_RECT[MONTH_PART_CODE] ) ;
  464.                     MoveTo( CONTROL_CHAR_POS[0].h, CONTROL_CHAR_POS[0].v ) ;
  465.                     DrawChar( CONTROL_CHAR_ARY[0] ) ;
  466.                     MoveTo( CONTROL_CHAR_POS[1].h, CONTROL_CHAR_POS[1].v ) ;
  467.                     DrawChar( CONTROL_CHAR_ARY[1] ) ;
  468.                     if( CONTROL_ITEM_HILITE[MONTH_PART_CODE] ) {
  469.                         InvertRect( &CONTROL_ITEM_RECT[MONTH_PART_CODE] ) ;
  470.                     }
  471.                     break ;
  472.                 case DAY_PART_CODE:
  473.                     /* Draw day characters */
  474.                     EraseRect( &CONTROL_ITEM_RECT[DAY_PART_CODE] ) ;
  475.                     MoveTo( CONTROL_CHAR_POS[3].h, CONTROL_CHAR_POS[3].v ) ;
  476.                     DrawChar( CONTROL_CHAR_ARY[3] ) ;
  477.                     MoveTo( CONTROL_CHAR_POS[4].h, CONTROL_CHAR_POS[4].v ) ;
  478.                     DrawChar( CONTROL_CHAR_ARY[4] ) ;
  479.                     if( CONTROL_ITEM_HILITE[DAY_PART_CODE] ) {
  480.                         InvertRect( &CONTROL_ITEM_RECT[DAY_PART_CODE] ) ;
  481.                     }
  482.                     break ;
  483.                 case YEAR_PART_CODE:
  484.                     /* Draw year characters */
  485.                     EraseRect( &CONTROL_ITEM_RECT[YEAR_PART_CODE] ) ;
  486.                     MoveTo( CONTROL_CHAR_POS[6].h, CONTROL_CHAR_POS[6].v ) ;
  487.                     DrawChar( CONTROL_CHAR_ARY[6] ) ;
  488.                     MoveTo( CONTROL_CHAR_POS[7].h, CONTROL_CHAR_POS[7].v ) ;
  489.                     DrawChar( CONTROL_CHAR_ARY[7] ) ;
  490.                     if( CONTROL_ITEM_HILITE[YEAR_PART_CODE] ) {
  491.                         InvertRect( &CONTROL_ITEM_RECT[YEAR_PART_CODE] ) ;
  492.                     }
  493.                     break ;
  494.                 case HOUR_PART_CODE:
  495.                     /* Draw hour characters */
  496.                     EraseRect( &CONTROL_ITEM_RECT[HOUR_PART_CODE] ) ;
  497.                     MoveTo( CONTROL_CHAR_POS[8].h, CONTROL_CHAR_POS[8].v ) ;
  498.                     DrawChar( CONTROL_CHAR_ARY[8] ) ;
  499.                     MoveTo( CONTROL_CHAR_POS[9].h, CONTROL_CHAR_POS[9].v ) ;
  500.                     DrawChar( CONTROL_CHAR_ARY[9] ) ;
  501.                     if( CONTROL_ITEM_HILITE[HOUR_PART_CODE] ) {
  502.                         InvertRect( &CONTROL_ITEM_RECT[HOUR_PART_CODE] ) ;
  503.                     }
  504.                     break ;
  505.                 case MINUTE_PART_CODE:
  506.                     /* Draw minute characters */
  507.                     EraseRect( &CONTROL_ITEM_RECT[MINUTE_PART_CODE] ) ;
  508.                     MoveTo( CONTROL_CHAR_POS[11].h, CONTROL_CHAR_POS[11].v ) ;
  509.                     DrawChar( CONTROL_CHAR_ARY[11] ) ;
  510.                     MoveTo( CONTROL_CHAR_POS[12].h, CONTROL_CHAR_POS[12].v ) ;
  511.                     DrawChar( CONTROL_CHAR_ARY[12] ) ;
  512.                     if( CONTROL_ITEM_HILITE[MINUTE_PART_CODE] ) {
  513.                         InvertRect( &CONTROL_ITEM_RECT[MINUTE_PART_CODE] ) ;
  514.                     }
  515.                     break ;
  516.                 case UP_ARROW:
  517.                 case DOWN_ARROW:
  518.                     /* draw the arrows */
  519.                     SetRect( &box, CONTROL_ITEM_RECT[UP_ARROW].left, 
  520.                                    CONTROL_ITEM_RECT[UP_ARROW].top,
  521.                                    CONTROL_ITEM_RECT[DOWN_ARROW].right, 
  522.                                    CONTROL_ITEM_RECT[DOWN_ARROW].bottom ) ;
  523.                     /* If there are no items hilited then erase arrows */
  524.                     if( CONTROL_HILITED == 0 ) {
  525.                         EraseRect( &box ) ;
  526.                     }else{
  527.                         SetRect( &box2, 0,0,11,18 ) ;
  528.                         arrows.rowBytes = 2 ;
  529.                         arrows.bounds = box2 ;
  530.                         arrows.baseAddr = bits ;
  531.                         CopyBits( &arrows, &CONTROL_WINDOW->portBits, &box2, &box,
  532.                                   srcOr, NULL ) ;
  533.                     }
  534.                     break ;
  535.                 }
  536.             }
  537.         }
  538.         
  539.         /* Restore old clip region */
  540.         SetClip( OLD_CLIP ) ;
  541.     }
  542.     return ;
  543. }
  544. long doTestControl( pt, my_control )
  545. long pt ;
  546. ControlHandle my_control ;
  547. {
  548.     int i ;
  549.     long result = 0 ;
  550.     
  551.     for( i=1;i<NUM_PARTS;i++ ) {
  552.         if( PtInRect( pt, &CONTROL_ITEM_RECT[i] ) ) {
  553.             result = i ;
  554.             break ;
  555.         }
  556.     }
  557.     return result ;
  558. }
  559. void doCalcCRgns( region, my_control )
  560. RgnHandle region ;
  561. ControlHandle my_control ;
  562. {
  563.     RectRgn( (RgnHandle)region, &CONTROL_RECT ) ;
  564.     return ;
  565. }
  566. void doTrackControl( hilite, my_control )
  567. int hilite ;
  568. ControlHandle my_control ;
  569. {    
  570.     /* Is it in the arrows */
  571.     if( hilite == UP_ARROW || hilite == DOWN_ARROW ) {
  572.         /* Delay to keep from changing the numbers too fast */
  573.         if( DE_BOUNCER ) {
  574.             DE_BOUNCER-- ;
  575.             return ;
  576.         }
  577.         if( hilite == UP_ARROW ) {
  578.             switch( CONTROL_HILITED ) {
  579.             case MONTH_PART_CODE:
  580.                 if( CONTROL_DATE_TIME.month >= 12 ) {
  581.                     CONTROL_DATE_TIME.month = 1 ;
  582.                 }else CONTROL_DATE_TIME.month++ ;
  583.                 CONTROL_ITEM_UPDATE[MONTH_PART_CODE] = TRUE ;
  584.                 break ;
  585.             case DAY_PART_CODE:
  586.                 if( CONTROL_DATE_TIME.day >= NUM_DAYS[CONTROL_DATE_TIME.month-1] ) {
  587.                     CONTROL_DATE_TIME.day = 1 ;
  588.                 }else CONTROL_DATE_TIME.day++ ;
  589.                 CONTROL_ITEM_UPDATE[DAY_PART_CODE] = TRUE ;
  590.                 break ;
  591.             case YEAR_PART_CODE:
  592.                 if( CONTROL_DATE_TIME.year >= 1999 ) {
  593.                     CONTROL_DATE_TIME.year = 1904 ;
  594.                 }else CONTROL_DATE_TIME.year++ ;
  595.                 CONTROL_ITEM_UPDATE[YEAR_PART_CODE] = TRUE ;
  596.                 if( ( CONTROL_DATE_TIME.year % 4 ) == 0 ) {
  597.                     NUM_DAYS[1] = 29 ;
  598.                 }else{
  599.                     NUM_DAYS[1] = 28 ;
  600.                 }
  601.                 break ;
  602.             case HOUR_PART_CODE:
  603.                 if( CONTROL_DATE_TIME.hour >= 23 ) {
  604.                     CONTROL_DATE_TIME.hour = 0 ;
  605.                 }else CONTROL_DATE_TIME.hour++ ;
  606.                 CONTROL_ITEM_UPDATE[HOUR_PART_CODE] = TRUE ;
  607.                 break ;
  608.             case MINUTE_PART_CODE:
  609.                 if( CONTROL_DATE_TIME.minute >= 59 ) {
  610.                     CONTROL_DATE_TIME.minute = 0 ;
  611.                 }else CONTROL_DATE_TIME.minute++ ;
  612.                 CONTROL_ITEM_UPDATE[MINUTE_PART_CODE] = TRUE ;
  613.                 break ;
  614.             }
  615.         }else if( hilite == DOWN_ARROW ) {
  616.             switch( CONTROL_HILITED ) {
  617.             case MONTH_PART_CODE:
  618.                 if( CONTROL_DATE_TIME.month <= 1 ) {
  619.                     CONTROL_DATE_TIME.month = 12 ;
  620.                 }else CONTROL_DATE_TIME.month-- ;
  621.                 CONTROL_ITEM_UPDATE[MONTH_PART_CODE] = TRUE ;
  622.                 break ;
  623.             case DAY_PART_CODE:
  624.                 if( CONTROL_DATE_TIME.day <= 1 ) {
  625.                     CONTROL_DATE_TIME.day = NUM_DAYS[CONTROL_DATE_TIME.month-1] ;
  626.                 }else CONTROL_DATE_TIME.day-- ;
  627.                 CONTROL_ITEM_UPDATE[DAY_PART_CODE] = TRUE ;
  628.                 break ;
  629.             case YEAR_PART_CODE:
  630.                 if( CONTROL_DATE_TIME.year <= 1904 ) {
  631.                     CONTROL_DATE_TIME.year = 1999 ;
  632.                 }else CONTROL_DATE_TIME.year-- ;
  633.                 CONTROL_ITEM_UPDATE[YEAR_PART_CODE] = TRUE ;
  634.                 if( ( CONTROL_DATE_TIME.year % 4 ) == 0 ) {
  635.                     NUM_DAYS[1] = 29 ;
  636.                 }else{
  637.                     NUM_DAYS[1] = 28 ;
  638.                 }
  639.                 break ;
  640.             case HOUR_PART_CODE:
  641.                 if( CONTROL_DATE_TIME.hour <= 0 ) {
  642.                     CONTROL_DATE_TIME.hour = 23 ;
  643.                 }else CONTROL_DATE_TIME.hour-- ;
  644.                 CONTROL_ITEM_UPDATE[HOUR_PART_CODE] = TRUE ;
  645.                 break ;
  646.             case MINUTE_PART_CODE:
  647.                 if( CONTROL_DATE_TIME.minute <= 0 ) {
  648.                     CONTROL_DATE_TIME.minute = 59 ;
  649.                 }else CONTROL_DATE_TIME.minute-- ;
  650.                 CONTROL_ITEM_UPDATE[MINUTE_PART_CODE] = TRUE ;
  651.                 break ;
  652.             }
  653.         }
  654.         /* Reset delay */
  655.         DE_BOUNCER = DELAY ;
  656.         NEW_DATE_TIME = CONTROL_DATE_TIME ;
  657.         Date2Chars( &CONTROL_DATE_TIME, CONTROL_CHAR_ARY ) ;
  658.         doDrawControl( hilite, my_control ) ;
  659.     }else if( hilite >= 0 && hilite < UP_ARROW ) {
  660.         HiliteControl( my_control, hilite ) ;
  661.     }
  662.     return ;
  663. }